package com.mustafaiev.tair.cts.service;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.log4j.Logger;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Component;
import org.springframework.ui.velocity.VelocityEngineUtils;

import com.mustafaiev.tair.cts.constant.Constants;

@Component
public class EmailSendService {

	private static final String EMAIL_WAS_SENT_SUCCESSFULLY = "Email from %s to %s was sent successfully";

	private static final Logger LOGGER = Logger
			.getLogger(EmailSendService.class);

	private static final java.util.logging.Logger J_LOGGER = java.util.logging.Logger
			.getLogger(EmailSendService.class.getName());

	private final VelocityEngine velocityEngine;

	/**
	 * Constructor
	 */
	@Autowired
	public EmailSendService(final VelocityEngine velocityEngine) {
		this.velocityEngine = velocityEngine;
	}

	/**
	 * Sends e-mail using Velocity template for the body and the properties
	 * passed in as Velocity variables.
	 * 
	 * @param msg
	 *            The e-mail message to be sent, except for the body.
	 * @param templateVariables
	 *            Variables to use when processing the template.
	 */
	public void send(final SimpleMailMessage msg,
			final Map<Object, Object> templateVariables) {
		try {
			final Message message = getMessage(msg, templateVariables);
			Transport.send(message);
			LOGGER.info(String.format(EMAIL_WAS_SENT_SUCCESSFULLY,
					message.getFrom(), msg.getTo()[0]));
			J_LOGGER.info(String.format(EMAIL_WAS_SENT_SUCCESSFULLY,
					message.getFrom(), msg.getTo()[0]));
		} catch (final IOException e) {
			LOGGER.error(e.getLocalizedMessage(), e);
		} catch (final MessagingException e) {
			LOGGER.error(e.getLocalizedMessage(), e);
		}

	}

	private Message getMessage(final SimpleMailMessage msg,
			final Map<Object, Object> hTemplateVariables) throws IOException,
			MessagingException, AddressException {
		final Properties properties = getProperties();
		J_LOGGER.info("SMTP host: "
				+ properties.getProperty(Constants.EMAIL_SMTP_HOST));
		final Session session = getSession(properties);
		final Message message = new MimeMessage(session);
		generateMessage(msg, hTemplateVariables, properties, message);
		return message;
	}

	private void generateMessage(final SimpleMailMessage msg,
			final Map<Object, Object> templateVariables,
			final Properties properties, final Message message)
			throws MessagingException, AddressException {

		setToRecipients(msg, message);
		message.setFrom(new InternetAddress(properties
				.getProperty(Constants.EMAIL_USERNAME_PROPERTY)));
		message.setSubject(msg.getSubject());
		message.setText(getMessageBody(templateVariables));
		message.setHeader("content-type", "text/html");
		LOGGER.info("Email's body was created");
		J_LOGGER.info("Email's body was created");
	}

	private void setToRecipients(final SimpleMailMessage msg,
			final Message message) throws MessagingException, AddressException {
		final String[] to = msg.getTo();
		for (final String toAddress : to) {
			message.setRecipient(Message.RecipientType.TO, new InternetAddress(
					toAddress));
		}
	}

	private Session getSession(final Properties properties)
			throws NoSuchProviderException {
		final Session session = Session.getDefaultInstance(properties,
				new Authenticator() {
					@Override
					protected PasswordAuthentication getPasswordAuthentication() {
						return new PasswordAuthentication(
								properties
										.getProperty(Constants.EMAIL_USERNAME_PROPERTY),
								properties
										.getProperty(Constants.EMAIL_PASSWORD_PROPERTY));
					}
				});
		return session;
	}

	private String getMessageBody(final Map<Object, Object> templateVariables) {
		final String template = (String) templateVariables
				.get(Constants.EMAIL_TEMPLATE_FILE);
		final String body = VelocityEngineUtils.mergeTemplateIntoString(
				this.velocityEngine, template, templateVariables);
		return body;
	}

	private Properties getProperties() throws IOException {
		final Resource resource = new ClassPathResource("/mail.properties");
		final Properties properties = PropertiesLoaderUtils
				.loadProperties(resource);
		return properties;
	}

}
